/* eslint-disable complexity */
// 合并对象
export const merge = (...arg) => {
    if (arg.length === 0) {
        throw Error("merge error=>请传入需要合并的对象");
    }
    let target = arg[0] || {};
    let depath = false;
    const length = arg.length;
    let i = 1;

    if (Object.prototype.toString.call(target) === "[object Boolean]") {
        depath = target;
        target = arg[i];
        i++;
    }

    if (typeof target !== "object") {
        target = {};
    }

    if (i === 2 && length <= 1) {
        throw Error("merge error=>请传入需要合并的对象");
    }

    for (; i < length; i++) {
        const source = arg[i] || {};
        if (source != null) {
            for (const key in source) {
                if (Object.prototype.hasOwnProperty.call(source, key)) {
                    const src = target[key];
                    const copy = source[key];
                    if (target === copy) {
                        continue;
                    }
                    if (depath && copy && (isObject(copy) || Array.isArray(copy))) {
                        let clone;
                        if (Array.isArray(copy)) {
                            clone = src && Array.isArray(src) ? src : [];
                        } else {
                            clone = src && isObject(src) ? src : {};
                        }
                        target[key] = merge(depath, clone, copy);
                    } else if (copy !== void 0) {
                        target[key] = copy;
                    }
                }
            }
        }
    }
    return target;
};

export const isObject = target => Object.prototype.toString.call(target) === "[object Object]";
export const isEmptyObject = obj => {
    for (const key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            return false;
        }
    }
    return true;
};

// swiper的观察者模式
export class ObserverClass {
    constructor(params = {}) {
        const self = this;
        self.params = params;
        // Events
        self.eventsListeners = {};
        if (self.params && self.params.on) {
            Object.keys(self.params.on).forEach(eventName => {
                self.on(eventName, self.params.on[eventName]);
            });
        }
    }

    on(events, handler, priority) {
        const self = this;
        if (typeof handler !== "function") return self;
        const method = priority ? "unshift" : "push";
        events.split(" ").forEach(event => {
            if (!self.eventsListeners[event]) self.eventsListeners[event] = [];
            self.eventsListeners[event][method](handler);
        });
        return self;
    }

    off(events, handler) {
        const self = this;
        if (!self.eventsListeners) return self;
        events.split(" ").forEach(event => {
            if (typeof handler === "undefined") {
                self.eventsListeners[event] = [];
            } else {
                self.eventsListeners[event].forEach((eventHandler, index) => {
                    if (eventHandler === handler) {
                        self.eventsListeners[event].splice(index, 1);
                    }
                });
            }
        });
        return self;
    }

    emit(...args) {
        const self = this;
        if (!self.eventsListeners) return self;
        let events;
        let data;
        let context;
        if (typeof args[0] === "string" || Array.isArray(args[0])) {
            events = args[0];
            data = args.slice(1, args.length);
            context = self;
        } else {
            events = args[0].events;
            data = args[0].data;
            context = args[0].context || self;
        }
        const eventsArray = Array.isArray(events) ? events : events.split(" ");
        eventsArray.forEach(event => {
            if (self.eventsListeners && self.eventsListeners[event]) {
                const handlers = [];
                self.eventsListeners[event].forEach(eventHandler => {
                    handlers.push(eventHandler);
                });
                handlers.forEach(eventHandler => {
                    eventHandler.apply(context, data);
                });
            }
        });
        return self;
    }
}

export const debounce = (fn, delay = 100) => {
    let timer = null;
    let _args = null;
    let _ctx = null;
    const _fn = () => {
        fn.apply(_ctx, _args);
        timer = null;
    };
    return function (...args) {
        _ctx = this;
        _args = args;
        if (timer) {
            clearTimeout(timer);
            timer = null;
        }
        timer = setTimeout(_fn, delay);
    };
};

/**
 * 通过字符串操作将一个数放大或缩小指定倍数
 * @num 被转换的数
 * @m   放大或缩小的倍数，为正表示小数点向右移动，表示放大；为负反之
 */
export const numScale = (num, m) => {
    let parts = num.toString().split(".");

    const integerLen = parts[0].length;

    const decimalLen = parts[1] ? parts[1].length : 0;

    // 放大，当放大的倍数比原来的小数位大时，需要在数字后面补零
    if (m > 0) {
        // 补多少个零：m - 原始值的小数位数
        let zeros = m - decimalLen;
        while (zeros > 0) {
            zeros -= 1;
            parts.push(0);
        }
        // 缩小，当缩小的倍数比原来的整数位大时，需要在数字前面补零
    } else {
        // 补多少个零：m - 原始值的整数位数
        let zeros = Math.abs(m) - integerLen;
        while (zeros > 0) {
            zeros -= 1;
            parts.unshift(0);
        }
    }

    // 小数点位置，也是整数的位数:
    //    放大：原始值的整数位数 + 放大的倍数
    //    缩小：原始值的整数位数 - 缩小的倍数
    const index = integerLen + m;
    // 将每一位都拆到数组里，方便插入小数点
    parts = parts.join("").split("");
    // 当为缩小时，因为可能会补零，所以使用原始值的整数位数
    // 计算出的小数点位置可能为负，这个负数应该正好是补零的
    // 个数，所以小数点位置应该为 0
    parts.splice(index > 0 ? index : 0, 0, ".");

    return parseFloat(parts.join(""));
};

/**
 * 获取小数位数
 */
export const getExponent = num => (Math.floor(num) === num || !num.toString().split(".")[1] ? 0 : num.toString().split(".")[1].length);
/**
 * 两数相加
 */
export const askPlus = (num1, num2) => {
    const multiple = Math.max(getExponent(num1), getExponent(num2));
    return numScale(numScale(num1, multiple) + numScale(num2, multiple), multiple * -1);
};
/**
 * 两数相减
 */
export const askMinus = (num1, num2) => {
    const multiple = Math.max(getExponent(num1), getExponent(num2));
    return numScale(numScale(num1, multiple) - numScale(num2, multiple), multiple * -1);
};
/**
 * 两数相乘
 */
export const askTimes = (num1, num2) => {
    const multiple = Math.max(getExponent(num1), getExponent(num2));
    // const l1 = getExponent(num1);
    // const l2 = getExponent(num2);
    // return numScale((numScale(num1, multiple) * numScale(num2, multiple)) / Math.pow(10, l2 + l1),multiple * -1);
    return numScale(numScale(num1, multiple) * numScale(num2, multiple), multiple * 2 * -1);
};
/**
 * 两数相除
 */
export const askDiv = (num1, num2) => {
    const multiple = Math.max(getExponent(num1), getExponent(num2));
    // const l1 = getExponent(num1);
    // const l2 = getExponent(num2);
    // return numScale((numScale(num1, multiple) / numScale(num2, multiple)) * Math.pow(10, l2 - l1),multiple * -1);
    return numScale(num1, multiple) / numScale(num2, multiple);
};
